package com.chat.api.test.redisLock;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;

import java.util.List;
import java.util.UUID;

public class RedisLock {

    private JedisPool jedisPool;

    public RedisLock(JedisPool jedisPool){
        this.jedisPool = jedisPool;
    }

    /**
     * 添加锁
     * @param lock
     * @param requestTimeout
     * @param timeout
     * @return
     */
    public String addLock(String lock,Long requestTimeout,Long timeout){
        Jedis jedis = null;
        String identify = null;
        try {
            jedis = jedisPool.getResource();
            //生成一个随机val
            String val = UUID.randomUUID().toString();
            String key = lock;
            //锁的超时时间
            int expire = (int) (timeout/1000);
            //获取锁的超时时间,超过时长则停止获取
            long end = System.currentTimeMillis() + requestTimeout;
            while (System.currentTimeMillis() < end){
                if (jedis.setnx(key,val) == 1){
                    jedis.expire(key,expire);
                    //返回val，释放锁时进行确认
                    identify = val;
                    return identify;
                };
                //如果这里返回-1，则代表key没有过期时间，这里对key添加一个过期时间
                if (jedis.ttl(key) == -1){
                    jedis.expire(key,expire);
                }
                try {
                    Thread.sleep(10);
                }catch (Exception e){
                    Thread.currentThread().interrupt();
                }

            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (jedis != null){
                jedis.close();
            }
        }
        return identify;
    }

    /**
     * 释放锁
     * @param lock
     * @param identify
     * @return
     */
    public boolean releaseLock(String lock,String identify){
        Jedis jedis = null;
        String key = lock;
        boolean flag = false;
        try {
            jedis = jedisPool.getResource();
            while (true){
                //开始事务之前先监视key
                jedis.watch(key);
                //释放锁之前先判断是否是该锁
                if (identify.equals(jedis.get(key))){
                    //开始事务
                    Transaction transaction = jedis.multi();
                    transaction.del(key);
                    //提交事务
                    List<Object> exec = transaction.exec();
                    if (exec == null){
                        continue;
                    }
                    flag = true;
                    jedis.unwatch();
                    break;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (jedis != null){
                jedis.close();
            }
        }
        return flag;
    }



}
